/*
 * -------------------------------------- 
 * FileName: 2.stack.c 
 * Content:
 * 
 * Auther:  杨则瑞 
 * Encode:  utf-8 | CRLF                  
 * -------------------------------------- 
 */

#include<stdio.h>
#include<stack.h>
#include<dual_list.h>
#include<string.h>

typedef struct 
{
    char str[16];
}car_number_t;

stack_error_t parklotError;
stack_t parklot;
duList_error_t waitingQueueError;
duList_t waitingQueue;

void init()
{
    stack_init(&parklot,sizeof(car_number_t),&parklotError);
    duList_init(&waitingQueue, sizeof(car_number_t), &waitingQueueError);
    const char *mots = 
    "====================================================================== \n"\
    "      Task 2_1 :      Parklot Manage System  (linked list):            \n"\
    "---------------------------------------------------------------------- \n"\
    "    welcome! You can use \"help\" command to get helper docs           \n"\
    "                                                                       \n"\
    "                                                                       \n"\
    "====================================================================== \n";
    printf(mots);

}


static void cmd_out(const char *);
static void cmd_in(const char *);
static void cmd_help(const char *);
static void cmd_show(const char *);
static void cmd_quit(const char *);
static void cmd_list(const char *);


int n;
unsigned char running = 1;
int main(int argc, char *argv[])
{


    char cmd_buffer[1024];

    init();

    struct cmd_t {
        char command_name[20];
        void (*command)  (const char *);
    };

    struct cmd_t cmds[] = {
       {"out", cmd_out},
       {"in",  cmd_in},
       {"help", cmd_help},
       {"list", cmd_list},
       {"show", cmd_show},
       {"quit", cmd_quit}
    };

    running = 1;

    int voi = scanf("%d",&n);
    if(voi != 1 || n <= 0)
    {
        printf ("N is invalid.\n");
        running = 0;
        system("pause");
    }


    while(running)
    {
        printf("\r>");
        fflush(stdout);
        fgets(cmd_buffer,1000,stdin);

        char ins[20];
        int offset;

        int all_len = strlen(cmd_buffer);
        sscanf(cmd_buffer,"%19s%n",ins,&offset);

        unsigned char matched = 0;
        for(int i = 0; i < sizeof(cmds) / sizeof(struct cmd_t); ++ i)
        {
            // 传参前，需要保证加了偏移后的串是有效的。
            if(0 == strcmp(cmds[i].command_name,ins) && all_len > offset)
            {
                cmds[i].command(cmd_buffer+offset);
                matched = 1;
            }
        }
        if(matched == 0)
        {
            printf("unrecongized command: %19s\n",ins);
        }
    }
    return 0;
}

static void cmd_out(const char * _args)
{
    if(parklot._len <= 0)
    {
        printf("there is no car in the parklot.\n");
        return;
    }
    else
    {
        printf("\"%s\" is leaving.\n", stack_top(&parklot));
        stack_pop(&parklot);
        // 当 waiting queue 非空。
        if(1 != duList_is_empty(&waitingQueue))
        {
            // 把waitqueue的第一个移动到parklot里。
            duList_get(&waitingQueue,0,stack_push_get(&parklot));
            duList_erase(&waitingQueue,0);
        }
    }
}


static void cmd_in(const char * arg)
{
    char carnum[20] = {0};
    int voi = sscanf(arg , "%19s", carnum);

    // 用户没有输入车辆id时
    if(voi < 1)
    {
        printf("usage: \"in <car-id(nospace)>\" \n");
        return;

    }


    // 在栈里寻找
    unsigned char duplicate = 0;
    for(int i = 0; i < parklot._len && duplicate == 0; ++ i)
    {
        if(0==strcmp(parklot.data + i * parklot._elemSize, carnum))
        {
            duplicate = 1;
            break;
        }
    }

    // 在队列里寻找
    duList_node_t * siz = waitingQueue._header;
    duList_node_t * itr = siz->next;
    int cnt = 0;
    while (itr != siz && duplicate == 0)
    {
        if(0==strcmp((char *)itr->data, carnum))
        {
            duplicate = 1;
            break;
        }
        itr = itr->next;
        cnt ++;
    }

    // 出现重复
    if(duplicate)
    {
        printf("duplicate car number, neglected.\n");
        return;
    }

    if(parklot._len < n && duList_is_empty(&waitingQueue))
    {
        // 当parklot有空，队是空的时候直接进入parklot
        car_number_t * tmp = stack_push_get(&parklot);
        if (tmp != NULL)
        {
            memcpy(tmp,carnum,sizeof(carnum));
        }
    } 
    else
    {
        // 否则，进入队列
        duList_insert_reverse(&waitingQueue, 0, carnum);
    }

}

static void cmd_list(const char * _args)
{

    printf("Parklot:\n");
    for(int i = 0; i < parklot._len; ++ i)
    {
        printf("%d: [%s]\n",i, parklot.data + i * parklot._elemSize);
    }

    printf("Queue:\n");
    duList_node_t * siz = waitingQueue._header;
    duList_node_t * itr = siz->next;
    int cnt = 0;
    while (itr != siz)
    {
        printf("%d: [%s]\n", cnt, (char*)itr->data);
        itr = itr->next;
        cnt ++;
    }
    
}



static void cmd_quit(const char * _args)
{
    duList_uninit(&waitingQueue);
    stack_uninit(&parklot);
    running = 0;
    return;
}



static void cmd_help(const char * _args)
{
    const char * helping = 
    "======================================================================\n"
    "   out: \"out\"\n"
    "   in: \"in <car-id(nospace)>\" \n"
    "   help: \"help\" \n"
    "   list: \"list\" \n"
    "   show: \"show <car-id>\" \n"
    "   quit: \"quit\"\n"
    "======================================================================\n";


    printf(helping);
}


static void cmd_show(const char * arg)
{
    char carnum[20] = {0};
    int voi = sscanf(arg , "%19s", carnum);

    // 用户没有输入车辆id时
    if(voi < 1)
    {
        printf("usage: \"show <car-id(nospace)>\" \n");
        return;

    }

    unsigned char found = 0;
    const char *area = "nowhere";
    unsigned int pos = 0;

    // 在栈里寻找
    for(int i = 0; i < parklot._len && found == 0; ++ i)
    {
        if(0==strcmp(parklot.data + i * parklot._elemSize, carnum))
        {
            found = 1;
            area = "Parklot";
            pos = i;
            break;
        }
    }

    // 在队列里寻找
    duList_node_t * siz = waitingQueue._header;
    duList_node_t * itr = siz->next;
    int cnt = 0;
    while (itr != siz && found == 0)
    {
        if(0==strcmp((char *)itr->data, carnum))
        {
            found = 1;
            area = "Queue";
            pos = cnt;
            break;
        }
        itr = itr->next;
        cnt ++;
    }

    // 出现
    if(found)
    {
        printf("found \"%s\" in %s[%u].\n",carnum, area, pos);
        return;
    } 
    else
    {
        printf("not found.\n");
    }


}
